/* UniApo: Parser
 * filename:  main.cpp
 * date:      June 2010
 * author:    Jeffrey Geyssens
 * about:     This file contains implementation of the Parsing module.
 *            It provides the interface for creating parsers given a MAP file
 *            which is then used to translate SDS data strings.
 *            It can be invoked on it's own or by using the UI.
 * usage:     Parser -b pname x.MAP (creates a new parser called pname).
 *            Parser -c (shows current parser).
 *            Parser -s x (sets current parser to x).
 *            Parser -p x.SDS (parse SDS and display PMAP results).
 *
 *            As is the case in all UniApo file editors:
 *              h: displays hardcoded help content.
 *              s: builds file from objects and saves to disk.
 *              q: quit and return to OS.
 *
 * Marked as completed: 28th june 2010 and no changes since
 */
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include "../UniApoLib/SDSParser.h"

using namespace std;

int main(int argc, char** argv) {


    if (argc < 2) {
        cerr << "ERROR (Parser): Requires at least one argument" << endl;
        return 80;
    }
    //First read the config file
    //Getting the path of the parser config file
    char *path = NULL;
    path = getcwd(NULL, 0); // Get full absolute path of program
    string pathtemp = path;
    string::size_type loc1 = pathtemp.find("/UniApo/", 0);
    //Find UniApo in path.
    stringstream pconfig;
    string pconfigpath;
    pconfig << pathtemp.substr(0, loc1 + 8) << "Saves/parser.conf";
    //Append after UniApo
    pconfigpath = pconfig.str();
    //Data declarations for config file
    string current_parser, current_map, templine, tempp, tempm;
    map <string, string> parser_map_files;
    //Read the config file
    cout << "Reading config file... ";

    fstream configfile(pconfigpath.c_str());
    if (configfile.is_open()) {
        getline(configfile, current_parser);
        getline(configfile, templine);
        while (!configfile.eof()) {

            tempp = templine.substr(0, templine.find("::"));
            tempm = templine.substr(templine.find("::") + 2, templine.size());
            if (tempp == current_parser) {
                current_map = tempm;
            }

            parser_map_files.insert(pair<string, string > (tempp, tempm));
            getline(configfile, templine);
        }
        cout << "OK! " << endl;
        configfile.close();
    } else {
        cout << "ERROR (Parser): Missing Config file" << endl;
        return 81;

    }


    void processLine(string const & lineData);
    string option = argv[1];
    if ((option.size() != 2) || (option.at(0) != '-')) {
        cerr << "ERROR in 1st argument (Parser): Use -b to build new parser,";
        cerr << " -c to display current parser,";
        cerr << "-s to set current parser or -p to parse SDS" << endl;
        return 82;
    }

    //Display which parser is in use
    if (option.at(1) == 'c') {
        if (argc == 2) {

            cout << "Using Parser: " << current_parser << endl;
            cout << "Source MAP file: " << current_map << ".MAP" << endl;
            return 0;
        } else {
            cerr << "ERROR (Parser -c): Invalid amount of arguments";
            cerr << "Expects no arguments" << endl;
            return 83;
        }

    }

    //Set the current parser

    if (option.at(1) == 's') {
        if (argc == 3) {
            string current = argv[2];
            //Do nothing if the parser was already set as working parser
            if (current == current_parser) {
                return 0;
            }
            //Check if the parser exists
            map <string, string>::iterator configit;
            configit = parser_map_files.find(current);
            if (configit != parser_map_files.end()) {
                ofstream myfile(pconfigpath.c_str());
                if (myfile.is_open()) {
                    myfile << current << "\n";
                    for (configit = parser_map_files.begin();
                            configit != parser_map_files.end();
                            ++configit) {
                        myfile << (*configit).first << "::";
                        myfile << (*configit).second << "\n";
                    }
                    myfile.close();
                    cout << "Using Parser: " << current << endl;
                    return 0;

                } else {
                    cerr << "ERROR (Parser): No such parser available" << endl;
                    return 2;
                }

            } else {
                cerr << "ERROR (Parser -s): Parser has no MAP binding" << endl;
                return 84;
            }

        } else {
            cerr << "ERROR (Parser -s): Expects 1 argument " << endl;
            return 85;
        }
    }

    //Build a new parser

    if (option.at(1) == 'b') {
        if (argc != 4) {
            cerr << "ERROR (Parser): missing arguments" << endl;
            cerr << "(parsername and/or MAP file)" << endl;
            return 3;
        }
        string pname = argv[2];
        string file = argv[3];

        string filename = file.substr(0, file.size() - 4);
        string extension = file.substr(file.size() - 4, file.size());

        //First we check if a correct filename was supplied
        if (extension != ".MAP") {
            cerr << "ERROR (Parser): ";
            cerr << "Expected filename.MAP extension" << endl;
            return 86;
        }
        //Creating empty MAP object and MAPFile path for later
        MAPFile MAP;
        MAP.name(filename);

        //Load MAP file
        //TODO: make load files boolean
        MAP.loadFile();
        //Build parser
        MAP.buildParser(pname);

        //Add new data to config file

        //Edit the config file
        
        map <string, string>::iterator configit;
        configit = parser_map_files.find(pname);
        if (configit == parser_map_files.end()) {
            //Insert if not found
            parser_map_files.insert(pair<string, string > (pname, filename));
        }
          else {
            //Replace existing parser binding if already exists
            //TODO: Write a confirmation
            parser_map_files.erase(configit);
            parser_map_files.insert(pair<string, string > (pname, filename));
        }

     
        //Write to file
        ofstream myfile(pconfigpath.c_str());
        if (myfile.is_open()) {
            myfile << current_parser << "\n";
            for (configit = parser_map_files.begin();
                    configit != parser_map_files.end();
                    ++configit) {
                myfile << (*configit).first << "::";
                myfile << (*configit).second << "\n";
            }
            myfile.close();
        }


            cout << "The parser is available in /UniApo/Parser/" << pname << "/";
            cout << endl;
            cout << "To complete building process run \"sh build\" from shell ";
            cout << "at the parser location" << endl;

        }



        if (option.at(1) == 'p') {

            if (argc == 4) {


                //First we check if a parser is loaded and subsequently load
                //the parser
                string current;
                ifstream myfile(pconfigpath.c_str());
                if (myfile.is_open()) {
                    getline(myfile, current);
                    //Get corresponding MAPFile from parser
                    myfile.close();
                    cout << "Using Parser: " << current << endl;
                } else {
                    cerr << "ERROR (Parser) - Usage error" << endl;
                    cerr << "Parser -p filename.SDS" << endl;
                    return 87;
                }
                SDSParser();
                string file = argv[2]; //expecting file of type 'x.SDS'
                string filename = file.substr(0, file.size() - 4);
                string extension = file.substr(file.size() - 4, file.size());
                //First we check if a correct filetype was supplied
                if (extension != ".SDS") {
                    cerr << "ERROR (Parser): in file extension:" << endl;
                    cerr << "Expected filename.SDS extension" << endl;
                    return 88;
                }

                //Prepare files for parsing...
                SDSFile SDS;
                PDSFile PDS;
                MAPFile MAP;

                MAP.name(current_map);
                MAP.loadFile();

                SDS.name(filename);
                //Load file if exists
                SDS.loadFile();
                string pdsname = argv[3];
                PDS.name(pdsname);
                PDS.setSDS(SDS);
                PDS.setMAP(MAP);
                PDS.buildFile();

                SDSParser SP;
                SP.parseSDS(PDS, current_parser);


            } else {
                cerr << "ERROR (Parser): -p Expects 2 arguments:" << endl;
                cerr << "Parser -p <Filename>.SDS <SaveFile>" << endl;
                return 81;
            }

        }

        return 0;
    }


